/*
 * simes - simulador de escalonamento de processos
 * Copyright (C) 2006  Pablo A. Lerina Rodrigues
 *                     Armando Zaro
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "simes.h"

int size(vstring a) {
	int i;
	int cont=0;
	for (i=0; a[i]; i++)
		cont += 1;
	return cont;
}


int main(int argc, char **argv) {
	int i,j,k,tam, tem, id_recurso;

	// fila dos recursos
	//t_queue *recurso1 = malloc(sizeof(t_queue));
	//t_queue *recurso2 = malloc(sizeof(t_queue));
	//t_queue *recurso3 = malloc(sizeof(t_queue));
	//t_queue *recurso4 = malloc(sizeof(t_queue));
	//t_queue *recurso5 = malloc(sizeof(t_queue));
	
	// fila dos processos prontos
	t_queue *prontos = malloc(sizeof(t_queue));
	
	++argv;
	argc--; // tira o argv[0] (nome do programa) da lista
	tam = argc;
	string temp;
	t_queue *processos = malloc(sizeof(t_queue));
	processos->rear = NULL;
	processos->front = NULL;
	t_queue *processando = malloc(sizeof(t_queue));
	processando->rear = NULL;
	processando->front = NULL;
	t_qnode *p;
	t_processando *pcnd;
	t_processo *data;
	//string cod;


#ifdef DEBUG
	printf("numero de argumentos -> %d\n", argc);
#endif

	if (argc > 5) {
		printf("Numero de processos enviados(%d) maior do que o permitido(5) \n",argc);
		return -1;
	}

	for ( i=0; i<tam; i++) {
		temp = argv[i];
		if (!strstr(temp,",")) {
			fprintf(stderr, "Separador invalido. Use a virgula. \n");
			return -1;
		}
		// a cada iteracao de leitura dos argumentos prepara 
		// ponteiro para nodo processo
		data = malloc(sizeof(t_processo));
		data->estado = E;

		// Explode os args da linha de comando e preenche os
		temp = strtok(temp,",");
		if (temp) 
			data->entrada = atoi(temp);
		temp = strtok(NULL," ");
		if (temp) 
			data->id = atoi(temp);
		
		le_comandos(data); // associa pilha de comandos ao processo
		ordered_insert_pnode(processos, data); // insere na fila de processos ordenado por "entrada"
	}
#ifdef DEBUG_QUEUE
	print_queue(processos);
#endif

	i = 0;
	tem = 0;
	pcnd = (t_processando *)malloc(sizeof(t_processando));
	data = (t_processo *)malloc(sizeof(t_processo));
	data = remove_node(processos);
	printf("   \t1\t2\t3\t4\t5\tR1\tR2\tR4\tR5\n");
	do {
		printf("%03d:", i);
		if (data == NULL)
			printf("\n");
		else {
			// verifica na fila de processos se o tempo de entrada eh o atual
			if (data->entrada > i)
				printf("\t");
			else {
#ifdef DEBUG
				printf("%sprocesso %d %s\n", RED, data->id, NORMAL);
#endif				
				tem=1;
				t_snode *comando = pop(data->comandos); // tira da pilha de comandos 
				switch (comando->comando) {
					case PROCESSA:
						if (processando->rear == NULL)
							data->estado = P;
						else 
							data->estado = E;
						pcnd->processo = data;
						pcnd->cnt = comando->valor;
						insert_node(processando, pcnd);
					break;
					case DORME:
						//printf("dorme %d\n", comando->valor);
						data->estado = D;
					break;
					case ADQUIRE:
						//printf("adquire %d\n", comando->valor);
						// poem o processo na fila do recurso
					break;
					case LIBERA:
						//printf("libera %d\n", comando->valor);
						// remove o processo da fila de recurso
					break;

				}
				((t_processando *)processando->front->data)->cnt--;
				if (((t_processando*)processando->front->data)->cnt == 0) {
					// se o contador do processo que esta usando a CPU chega em 0
					// colocamos ele na fila de processos, mudamos seu estado e mudamos o estado do proximo
					t_processo *tmp_data = malloc(sizeof(t_processo));
					tmp_data = remove_node(processando);
					tmp_data->estado = E;
					insert_node(processos, tmp_data);
					// muda o estado do proximo na fila de processando
					((t_processando*)processando->front->data)->processo->estado = P;
				}

				// itera na fila de processos e recursos e exibe o estado de cada um
				t_qnode *tmp = malloc(sizeof(t_qnode));
				tmp = processando->front;
				printf("\t");
				int x;
				// itera nos processos
				for (x = 0; x < 5; x++) {
					data = (t_processo *)malloc(sizeof(t_processo));
					data = ((t_processando*)tmp->data)->processo;
#ifdef DEBUG					
					printf("processo: %d x: %d estado: %d", data->id, x+1, data->estado);
#endif					
					if (data->id == (x+1))
						printf("\t%s", estados[data->estado-1]);
					else
						printf("\t ");
					if (tmp->next != NULL)
						tmp = tmp->next;
					else break;	
				}
				printf("\n");
//				insert_node(prontos, data); // poem na fila de prontos

#ifdef DEBUG
				printf("Fila de prontos:\n");
				print_queue(prontos);
#endif
			}
		}
		if (tem) {
			// recupera da fila outro processo
			data = remove_node(processos);
		}
		tem = 0;
		sleep(1);
	} while ( (i += 1) <= 100 );
	return 0;
}

/*
 * Recebe ponteiro do processo. 
 * Abre arquivo do processo e le comandos.
 * Associa a pilha de comandos ao nodo do processo.
 */
void le_comandos(t_processo *p) {
	FILE *fp;
	string cmd;
	string num;
	string tmp = malloc(10*sizeof(string));
	sprintf(tmp, "%d", p->id);
	string name = strcat(tmp,".txt");
#ifdef DEBUG
	printf("nome do arquivo %s id:%d \n", name, p->id);
#endif

	if ((fp = fopen(name, "r")) == NULL) {
		fprintf(stderr, "Erro ao abrir o arquivo.\n");
		perror(name);
		exit(-1);
	}

	// carrega comandos na pilha e depois 
	// anexa a pilha ao processo
	t_stack *comandos = malloc(sizeof(t_stack));
	t_snode *nodo = malloc(sizeof(t_snode));
	cmd = malloc(sizeof(char));
	num = malloc(sizeof(char));
	while (fscanf(fp, "%s %c", cmd, num)) {
#ifdef DEBUG
		printf("%s %d\n", cmd, atoi(num));
#endif

		nodo->comando = id_cmd(cmd);
		nodo->valor = atoi(num);
		push(nodo, comandos);
		nodo = malloc(sizeof(t_snode));

		if (id_cmd(cmd) == FIM)
			break;
		cmd = malloc(sizeof(char));
		num = malloc(sizeof(char));
	}
	p->comandos = comandos;
}


INLINE int id_cmd(char *cmd) {
	if (strcmp(cmd, "processa") == 0)
		return PROCESSA;
	else if (strcmp(cmd, "dorme") == 0)
		return DORME;
	else if (strcmp(cmd, "adquire") == 0)
		return ADQUIRE;
	else if (strcmp(cmd, "libera") == 0)
		return LIBERA;
	else if (strcmp(cmd, "fim") == 0)
		return FIM;
	else
		return 0;
}
